package com.baijiaoxi.common.model.query;

import com.baijiaoxi.common.constant.SQLKey;
import com.baijiaoxi.common.utils.jdk.Strings;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public interface DynamicQueryBuilder<T extends DynamicCondition<T>> {
    static String regex = "(and|or|\\(|\\)|\\s)*";

    static boolean filterValid(String filterSql) {
        return !filterSql.matches(regex);
    }

    default String appendFilterAsString(T condition) {
        return appendFilterAsStringBuilder(condition).toString();
    }

    default StringBuilder appendFilterAsStringBuilder(T condition) {
        StringBuilder stringBuilder = new StringBuilder();
        if (condition == null)
            return stringBuilder;
        if (Strings.isNotBlank(condition.getLogicMethod()) && condition.getChildren() != null && !condition.getChildren().isEmpty()) {
            List<String> childrenFilterList = condition.getChildren().stream().map(childCondition -> {
                return appendFilterAsStringBuilder(childCondition).toString();
            }).filter(filterSql -> DynamicQueryBuilder.filterValid(filterSql)).toList();
            if (childrenFilterList != null && !childrenFilterList.isEmpty()) {
                stringBuilder.append(" ");
                if (condition.getLogicMethod().equalsIgnoreCase("and"))
                    stringBuilder.append(String.join(" and ", childrenFilterList));
                else if (condition.getLogicMethod().equalsIgnoreCase("or"))
                    stringBuilder.append("(").append(String.join(" or ", childrenFilterList)).append(")");
            }
        } else
            //具体条件
            stringBuilder.append(appendCondition(condition));
        return stringBuilder;
    }

    default StringBuilder appendCondition(T condition) {
        StringBuilder stringBuilder = new StringBuilder();
        String propertyName = condition.getPropertyName();
        if (Strings.isBlank(propertyName))
            return stringBuilder;

        String value = String.format("'%s'", Strings.nullToEmpty(condition.getValue()));
        String compareMethod = condition.getMethod() == null ? SQLKey.SqlCompareMethod.equals : condition.getMethod();

        switch (compareMethod) {
            case SQLKey.SqlCompareMethod.in:
                stringBuilder.append(String.format(" %s in(%s)", propertyName, condition.getValue()));
                break;
            case SQLKey.SqlCompareMethod.notIn:
                stringBuilder.append(String.format(" %s not in(%s)", propertyName, condition.getValue()));
                break;
            case SQLKey.SqlCompareMethod.blank:
                stringBuilder.append(String.format(" (%s is null or %s ='')", propertyName, propertyName));
                break;
            case SQLKey.SqlCompareMethod.notBlank:
                stringBuilder.append(String.format(" %s is not null and %s !=''", propertyName, propertyName));
                break;
            case SQLKey.SqlCompareMethod.equals:
                stringBuilder.append(" ").append(propertyName);
                stringBuilder.append(" = ").append(value);
                break;
            case SQLKey.SqlCompareMethod.include:
                stringBuilder.append(String.format(" instr(%s,%s)>0 ", propertyName, value));
                break;
            case SQLKey.SqlCompareMethod.exclude:
                stringBuilder.append(String.format(" instr(%s,%s)=0 ", propertyName, value));
                break;
            case SQLKey.SqlCompareMethod.greater:
                stringBuilder.append(String.format(" %s>%s ", propertyName, value));
                break;
            case SQLKey.SqlCompareMethod.greaterOrEquals:
                stringBuilder.append(String.format(" %s>=%s ", propertyName, value));
                break;
            case SQLKey.SqlCompareMethod.less:
                stringBuilder.append(String.format(" %s<%s ", propertyName, value));
                break;
            case SQLKey.SqlCompareMethod.lessOrEquals:
                stringBuilder.append(String.format(" %s<=%s ", propertyName, value));
                break;
        }


        return stringBuilder;
    }


    static DynamicQuery buildIn(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.in, value);
    }

    static DynamicQuery buildIn(String propertyName, String value, String... values) {
        List<String> valueList = Arrays.stream(values).filter(val -> Strings.isNotBlank(val)).collect(Collectors.toList());
        valueList.add(value);
        String realValue = String.join(",", valueList);
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.in, realValue);
    }


    static DynamicQuery buildNotIn(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.notIn, value);
    }

    static DynamicQuery buildNotIn(String propertyName, String value, String... values) {
        List<String> valueList = Arrays.stream(values).filter(val -> Strings.isNotBlank(val)).collect(Collectors.toList());
        valueList.add(value);
        String realValue = String.join(",", valueList);
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.notIn, realValue);
    }

    static DynamicQuery buildBlank(String propertyName) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.blank);
    }

    static DynamicQuery buildNotBlank(String propertyName) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.notBlank);
    }

    static DynamicQuery buildEquals(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.equals, value);
    }

    static DynamicQuery buildInclude(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.include, value);
    }

    static DynamicQuery buildExclude(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.exclude, value);
    }

    static DynamicQuery buildGreater(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.greater, value);
    }

    static DynamicQuery buildGreaterOrEquals(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.greaterOrEquals, value);
    }

    static DynamicQuery buildLess(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.less, value);
    }

    static DynamicQuery buildLessOrEquals(String propertyName, String value) {
        return new DynamicQuery(propertyName, SQLKey.SqlCompareMethod.lessOrEquals, value);
    }
}
